﻿using System;
using System.Collections.Generic;
using System.Text;
using TrippleGameDAL;
using System.Linq;
using System.Transactions;

namespace TrippleGameChallange
{
    public class TrippleGame
    {
        const int SIZE_Y = 5;
        const int SIZE_X = 10;
        const int BOARD_SIZE = 50;
        const string AWAITING = "AWAITING";
        const string PLAYER1_WON = "Winner:A";
        const string PLAYER2_WON = "Winner:B";
        const string DRAW = "Draw";
        public const char P1 = 'a';
        public const char P2 = 'b';
        const string ENDED = "ENDED";

        public const char EMPTY_CELL = ' ';
        private TripleGameEntities entitiesInternal;
        private Game game;

        public TripleGameEntities Entities
        {
            get
            {
                return entitiesInternal;
            }
            set
            {
                entitiesInternal = value;
            }
        }

        public Game Game
        {
            get
            {
                return game;
            }
            set
            {
                game = value;
            }
        }

        public static char? GetPlayerLetter(int gameId)
        {
            TripleGameEntities entities = new TripleGameEntities();

            return entities.Games.FirstOrDefault(g => g.GameId == gameId).PlayerTurn;
        }

        public static Game GetGame(int id , TripleGameEntities entities)
        {
            return entities.Games.FirstOrDefault(g => g.GameId == id);
        }

        public static string WhichPlayerTurn(char playerLetter, string matrix, int gameId)
        {
            char enemyLetter = playerLetter == P1 ? P2 : P1;
            TripleGameEntities entities = new TripleGameEntities();
            Game game = entities.Games.FirstOrDefault(g => g.GameId == gameId);

                if (HasTurns(enemyLetter, matrix))
                {
                    game.PlayerTurn = enemyLetter;
                    entities.SaveChanges();
                    return enemyLetter.ToString();
                }
                if (HasTurns(playerLetter, matrix))
                {
                    game.PlayerTurn = playerLetter;
                    entities.SaveChanges();
                    return playerLetter.ToString();
                }

            game.State = GetWinner(matrix);
            entities.SaveChanges();
            return game.State;
        }

        private static string GetWinner(string matrix)
        {
            int counterA = 0;
            int counterB = 0;

            string matrixLower = matrix.ToLower();

            for (int i = 0; i < matrixLower.Length; i++)
            {
                if (matrixLower[i] == P1)
                {
                    counterA++;
                }
                else if (matrixLower[i] == P2)
                {
                    counterB++;
                }
            }

            if (counterA > counterB)
            {
                return PLAYER1_WON;
            }
            else if (counterB > counterA)
            {
                return PLAYER2_WON;
            }
            else
            {
                return DRAW;
            }
        }

        private static bool HasTurns(char letter, string matrix)
        {
            for (int i = 0; i < SIZE_Y; i++)
            {
                for (int j = 0; j < SIZE_X; j++)
                {
                    if (IsMoveAllowed(j, i, j, i + 2, letter, matrix))
                    {
                        return true;
                    }
                    if (IsMoveAllowed(j, i, j + 2, i, letter, matrix))
                    {
                        return true;
                    }

                    if (IsMoveAllowed(j, i, j + 2, i + 2, letter, matrix))
                    {
                        return true;
                    }

                    if (IsMoveAllowed(j, i, j + 2, i - 2, letter, matrix))
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        public static void CreateGame(string name)
        {
            StringBuilder gameMatrix = new StringBuilder(new string (EMPTY_CELL, BOARD_SIZE));

            Game newGame = new Game()
            {
                Name = name,
                Matrix = gameMatrix.ToString(),
                State = AWAITING,
                PlayerTurn = P1
            };


            TripleGameEntities entities = new TripleGameEntities();
            entities.Add(newGame);
            entities.SaveChanges();
        }

        public static List<Game> LoadGames()
        {
            TripleGameEntities entities = new TripleGameEntities();
            var games = entities.Games.Where(g=>g.State != PLAYER1_WON && g.State != PLAYER2_WON &&
                g.State != DRAW);
            return games.ToList();
        }

        public static Game GetGameByID(int id)
        {
            TripleGameEntities entities = new TripleGameEntities();
            Game game= entities.Games.FirstOrDefault(g => g.GameId == id);
            return game;
        }

        public static Player CreatePlayer(string playerName)
        {
            TripleGameEntities entities = new TripleGameEntities();
            using (entities)
            {
                Guid playerGuid = Guid.NewGuid();
                Player player = new Player()
                {
                    PlayerId = playerGuid,
                    Name = playerName,
                };
                entities.Add(player);
                entities.SaveChanges();

                return player;
            }
        }

        public static string PerformMove(int startX, int startY, int endX, int endY, char playerLetter, string matrix)
        {
            StringBuilder gameMatrix = new StringBuilder(matrix);
            gameMatrix = ToLowerStringBuilder(gameMatrix);

            int startXConverted = startX;
            int startYConverted = startY * SIZE_X;
            int endXConverted = endX;
            int endYConverted = endY * SIZE_X;
            int middleX = (startXConverted + endXConverted) / 2;
            int middleY = (startYConverted + endYConverted) / 2;
            string letter = playerLetter.ToString().ToUpper();

            if (IsMoveAllowed(startX, startY, endX, endY, playerLetter, gameMatrix.ToString()))
            {
                gameMatrix[startXConverted + startYConverted] = letter[0];
                gameMatrix[middleX + middleY] = letter[0];
                gameMatrix[endXConverted + endYConverted] = letter[0];

                return gameMatrix.ToString();
            }
            return string.Format("Invalid move");
        }

        private static StringBuilder ToLowerStringBuilder(StringBuilder sb)
        {
            string last = sb.ToString();
            sb.Clear();
            sb.Append(last.ToLower());
            return sb;
        }

        private static char[,] ConvertToMatrix(string matrix)
        {
            char[,] converted = new char[SIZE_Y, SIZE_X];
            for (int i = 0; i < SIZE_Y; i++)
            {
                for (int j = 0; j < SIZE_X; j++)
                {
                    converted[i, j] = matrix[i * 10 + j];
                }
            }
            return converted;
        }

        private static bool IsMoveAllowed(int startX, int startY, int endX, int endY, char playerLetter, string matrix)
        {
            char[,] converted = ConvertToMatrix(matrix.ToLower());
            bool outsideMatrix = startX < 0 || startY < 0 || endX < 0 || endY < 0 || startX >= SIZE_X ||
                startY >= SIZE_Y || endX >= SIZE_X || endY >= SIZE_Y;
            if (outsideMatrix)
            {
                return false;
            }

            char enemyLetter = playerLetter == P1 ? P2 : P1;
            int middleX = (startX + endX) / 2;
            int middleY = (startY + endY) / 2;

            if (converted[startY, startX] == TrippleGame.EMPTY_CELL ||
               converted[middleY, middleX] == TrippleGame.EMPTY_CELL ||
               converted[endY, endX] == TrippleGame.EMPTY_CELL)
            {
                if (converted[startY, startX] != enemyLetter &&
                    converted[middleY, middleX] != enemyLetter &&
                    converted[endY, endX] != enemyLetter)
                {
                    return true;
                }
            }
            return false;
        }



        public static void JoinGame(Guid playerId,TripleGameEntities entity, Game gameToJoin, char letter)
        {
            
            if (letter == P1)
            {
                Player player = entity.Players.FirstOrDefault(p=>p.PlayerId.Equals(playerId));
                gameToJoin.Player1Id = player.PlayerId;
                gameToJoin.State = "AWAITING PLAYER 2";
            }
            else if (letter == P2)
            {
                    Player player = entity.Players.FirstOrDefault(p => p.PlayerId.Equals(playerId));
                    gameToJoin.Player2Id = player.PlayerId;
                    gameToJoin.State = "STARTED";
            }
            
        }

        public static void UpdateDatabase(Game game, string matrix, TripleGameEntities entities)
        {
            game.Matrix = matrix;
            entities.SaveChanges();
        }
    }
}
